﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Web;
using BbqFramework;
using System.IO;
using System.Net;

namespace Bbq.Gallery.UI
{
    /// <summary>
    /// External Resource Download HttpHandler
    /// </summary>
    /// <example>
    /// To register the ExternalResourceDownloadHandler with your application, 
    /// add the following to the <system.web> section of your web.config.
    /// <!-- Register the External Resource Download HttpHandler -->
    /// <httpHandlers>
    /// <add verb="GET" path="ExternalResourceDownloadHandler.ashx" type="Bbq.Gallery.UI.ExternalResourceDownloadHandler"/>
    /// </httpHandlers>
    /// </example>
    public class ExternalResourceDownloadHandler : IHttpAsyncHandler
    {
        #region IHttpHandler Members

        /// <summary>
        /// Gets a value indicating whether another request can use the <see cref="T:System.Web.IHttpHandler"></see> instance.
        /// </summary>
        /// <value></value>
        /// <returns>true if the <see cref="T:System.Web.IHttpHandler"></see> instance is reusable; otherwise, false.</returns>
        public bool IsReusable
        {
            get { return false; }
        }

        /// <summary>
        /// Enables processing of HTTP Web requests by a custom HttpHandler that implements the <see cref="T:System.Web.IHttpHandler"></see> interface.
        /// </summary>
        /// <param name="context">An <see cref="T:System.Web.HttpContext"></see> object that provides references to the intrinsic server objects (for example, Request, Response, Session, and Server) used to service HTTP requests.</param>
        public void ProcessRequest(HttpContext context)
        {
        }

        #endregion

        private delegate object DownloadDelegate(HttpContext context);

        #region Private fields
        private string _url = null;
        private Exception _ex = null;
        private HttpHandlerAsyncResult _ar = null;
        private DownloadDelegate _donwloadResult = null;
        #endregion

        #region IHttpAsyncHandler Members

        /// <summary>
        /// Begins the process request.
        /// </summary>
        /// <param name="context">The context.</param>
        /// <param name="cb">The cb.</param>
        /// <param name="extraData">The extra data.</param>
        /// <returns></returns>
        public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData)
        {
            // Instantiate a HttpHandlerAsyncResult
            _ar = new HttpHandlerAsyncResult(cb, extraData);

            _donwloadResult = new DownloadDelegate(this.Download);
            _donwloadResult.BeginInvoke(context, new AsyncCallback(this.DownloadCompleted), context);

            // Return an IAsyncResult that delays EndProcessRequest until
            // the final asynchronous Web service call has completed
            return _ar;
        }

        /// <summary>
        /// Provides an asynchronous process End method when the process ends.
        /// </summary>
        /// <param name="result">An <see cref="T:System.IAsyncResult"/> that contains information about the status of the process.</param>
        public void EndProcessRequest(IAsyncResult result)
        {
            if (_ex != null)
            {
                // If an exception was thrown, rethrow it
                throw _ex;
            }
        }

        #endregion

        private void DownloadCompleted(IAsyncResult ar)
        {
            if (_ex == null)
            {
                //Analyze HTTP response
                HttpContext context = (HttpContext)ar.AsyncState;
                HttpRequest request = context.Request;
                //Sets the response for thumbnail
                HttpResponse response = context.Response;
                response.Clear(); 
                response.BufferOutput = false;  //don't need buffer for image data.
                response.Cache.SetExpires(DateTime.Now.AddMinutes(15));
                response.Cache.SetCacheability(HttpCacheability.Public);
                response.Cache.SetSlidingExpiration(true);

                object result = _donwloadResult.EndInvoke(ar);
                if (result != null)
                {
                    response.ContentType = "application/octet-stream";
                    response.AddHeader("Content-Disposition", "attachment; filename=" + HttpUtility.UrlPathEncode(Path.GetFileName(_url)));

                    Stream stream = (Stream)result;
                    byte[] buffer = new byte[4096];
                    int readCount = 0;
                    while ((readCount = stream.Read(buffer, 0, 4096)) > 0)
                    {
                        response.OutputStream.Write(buffer, 0, readCount);
                    }

                    stream.Close();
                }
            }
        }

        private object Download(HttpContext context)
        {
            try
            {
                _url = context.Request.QueryString["url"];

                WebRequest imgRequest = WebRequest.Create(_url);
                WebResponse imgResponse = imgRequest.GetResponse();

                return imgResponse.GetResponseStream();
            }
            catch (Exception ex)
            {
                _ex = ex;
                _ar.CompleteCall();
                return null;
            }
        }
    }
}
